﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace TwitterAPI
{
    public class TwitterService
    {
        public event EventHandler<UsersCountEventArgs> UsersCountChanged;

        private Client twitterClient;
        private HashCodeItem hashCode = new HashCodeItem();
        private Dictionary<string, List<Action<IEnumerable<FeedItem>>>> commands = new Dictionary<string, List<Action<IEnumerable<FeedItem>>>>();

        public void Login(string username, string password)
        {
            this.twitterClient = new Client(username, password);
        }

        public void Login(ICredentials credentials)
        {
            this.twitterClient = new Client(credentials);
        }

        public string HashCode
        {
            get { return this.hashCode.HashCode; }
            set
            {
                hashCode.HashCode = value;
                Reset();
            }
        }

        public void Reset()
        {
            this.hashCode.Reset();
        }

        public int GetUsersCount()
        {
            return this.hashCode.Users.Count();
        }

        public void RegisterCommand(string command, Action<IEnumerable<FeedItem>> handler)
        {
            if (!commands.ContainsKey(command))
            {
                commands.Add(command, new List<Action<IEnumerable<FeedItem>>>());
            }

            commands[command].Add(handler);
        }

        public void ProcessMessages(Action<Exception> errorCallback)
        {
            List<FeedItem> feeds = TwitterAPI.Client.GetTwitsByHashCode(hashCode.HashCode, hashCode.SinceId);
            if (feeds.Count > 0)
            {
                ProcessUsersCount(feeds);

                hashCode.SinceId = feeds.Max<FeedItem>(feed => feed.Id);
                foreach (string command in this.commands.Keys)
                {
                    IEnumerable<FeedItem> commandFeeds = feeds.Where(feed => feed.Text.StartsWith(GetMessageWithHashcode(command), StringComparison.OrdinalIgnoreCase));

                    if (commandFeeds.Count() > 0)
                    {
                        foreach (var handler in this.commands[command])
                        {
                            try
                            {
                                handler(commandFeeds);
                            }
                            catch(Exception ex)
                            {
                                errorCallback(ex);
                            }
                        }
                    }
                }
            }
        }

        private void ProcessUsersCount(List<FeedItem> feeds)
        {
            int oldUsersCount = this.GetUsersCount();
            feeds.Select(feed => feed.User).Distinct().ToList().ForEach(user => hashCode.AddUser(user));
            int newUsersCount = this.GetUsersCount();

            if (oldUsersCount != newUsersCount)
            {
                OnUsersCountChanged(new UsersCountEventArgs(oldUsersCount, newUsersCount));
            }
        }

        protected virtual void OnUsersCountChanged(UsersCountEventArgs e)
        {
            if (UsersCountChanged != null)
            {
                UsersCountChanged(this, e);
            }
        }

        public string GetMessageWithHashcode(string message)
        {
            string result = HashCode + " " + message;

            if (!result.StartsWith("#"))
            {
                result = "#" + result;
            }

            return result;
        }

        public List<string> GetMessagesWithHashcode(string message)
        {
            List<string> messages = new List<string>();
            string tempHashCode = (HashCode.StartsWith("#") ? "" : "#") + HashCode + " ";
            int twitterSizeWithHashCode = 140 - tempHashCode.Length;

            while (message.Length > 0)
            {
                int cropPosition = Math.Min(message.Length, twitterSizeWithHashCode);
                messages.Add(tempHashCode + message.Substring(0, cropPosition));
                message = message.Substring(cropPosition);
            }

            return messages;
        }

        public void UpdateStatus(string message)
        {
            this.twitterClient.UpdateStatus(message);
        }

        public void UpdateStatus(List<string> messages)
        {
            messages.Reverse<string>().ToList().ForEach(message => this.twitterClient.UpdateStatus(message));
        }

        class HashCodeItem
        {
            private List<string> users = new List<string>();

            public string HashCode { get; set; }
            public long SinceId { get; set; }

            public IEnumerable<string> Users { get { return this.users; } }

            public void AddUser(string user)
            {
                if (!users.Contains(user))
                {
                    this.users.Add(user);
                }
            }

            public void Reset()
            {
                this.SinceId = 0;
                this.users = new List<string>();
            }
        }
    }
}
